package com.parkingwang.keyboard.view;

import com.parkingwang.keyboard.AttrFieldName;
import com.parkingwang.keyboard.AttrUtils;
import com.parkingwang.keyboard.HmsResourcesManager;
import com.parkingwang.keyboard.ResourceTable;
import com.parkingwang.keyboard.annotation.ColorInt;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.TextTool;
import ohos.app.Context;
import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class InputView extends DirectionalLayout implements Component.DrawTask {
    private static final String KEY_INIT_NUMBER = "pwk.keyboard.key:init.number";
    private InputDirectionalLayout pwkInputView = null;

    private final HashMap<String, Object> mKeyMap = new HashMap<>();

    private final Set<OnFieldViewSelectedListener> mOnFieldViewSelectedListeners = new HashSet<>(4);

    private FieldViewGroup mFieldViewGroup;

    /**
     * 点击选中输入框时，只可以从左到右顺序输入，不可隔位
     */
    private final ClickedListener mOnFieldViewClickListener = new ClickedListener() {
        @Override
        public void onClick(Component v) {
            final Button field = (Button) v;
            final ClickMeta clickMeta = getClickMeta(field);
            final int numberLength = mFieldViewGroup.getText().length();

            // 空车牌只能点击第一个
            if (numberLength == 0 && clickMeta.clickIndex != 0) {
                return;
            }

            // 不可大于车牌长度
            if (clickMeta.clickIndex > numberLength) {
                return;
            }

            // 点击位置是否变化
            if (clickMeta.clickIndex != clickMeta.selectedIndex) {
                setFieldViewSelected(field);
            }

            // 触发选中事件
            for (OnFieldViewSelectedListener listener : mOnFieldViewSelectedListeners) {
                listener.onSelectedAt(clickMeta.clickIndex);
            }
        }
    };

    @Nullable
    private SelectedDrawable mSelectedDrawable;

    public InputView(Context context) {
        super(context);
    }

    public InputView(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    /**
     * 构造挂载button在上面
     *
     * @param context Env
     * @param attrSet 属性集合
     * @param styleName 风格名称
     */
    public InputView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        addDrawTask(this);
        pwkInputView = (InputDirectionalLayout) LayoutScatter.getInstance(context).parse(ResourceTable.Layout_pwk_input_view, null, true);
        addComponent(pwkInputView);
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setCornerRadius(HmsResourcesManager.getFloatValueByResources(context, ResourceTable.Float_pwk_input_item_radius));
        shapeElement.setStroke((int) HmsResourcesManager.getFloatValueByResources(context, ResourceTable.Float_pwk_input_view_border_width),
                RgbColor.fromArgbInt(Color.getIntColor("#d8d8d8")));
        pwkInputView.setBackground(shapeElement);
        mFieldViewGroup = new FieldViewGroup() {
            @Override
            protected Button findViewById(int id) {
                Button componentById = (Button) InputView.this.findComponentById(id);
                componentById.setTextColor(Color.BLACK);
                componentById.setTextSize(21, Text.TextSizeType.FP);
                componentById.setFont(new Font.Builder("").setWeight(Font.MEDIUM).build());
                return componentById;
            }
        };
        onInited(context, attrSet);
    }

    private void onInited(Context context, AttrSet attrs) {
        final float textSize = AttrUtils.getDimensionValueByAttr(attrs, AttrFieldName.INPUTVIEW_PWKINPUTTEXTSIZE, 21);
        final String drawableClassName = AttrUtils.getStringValueByAttr(attrs, AttrFieldName.INPUTVIEW_PWKSELECTEDDRAWABLE, SelectedDrawable.class.getName());
        final int itemBorderSelectedColor = AttrUtils.getColorValueByAttr(attrs, AttrFieldName.INPUTVIEW_PWKITEMBORDERSELECTEDCOLOR, new Color(HmsResourcesManager.getColorValueByResources(context, ResourceTable.Color_pwk_keyboard_primary_color))).getValue();
        initSelectedDrawable(drawableClassName, itemBorderSelectedColor);

        mFieldViewGroup.setupAllFieldsTextSize(textSize);
        mFieldViewGroup.setupAllFieldsOnClickListener(mOnFieldViewClickListener);
        mFieldViewGroup.changeTo7Fields();
    }

    private void initSelectedDrawable(String className, int selectedColor) {
        if (TextTool.isNullOrEmpty(className)) {
            return;
        }
        mSelectedDrawable = new SelectedDrawable(null, true);
        mSelectedDrawable.setColor(selectedColor);
        mSelectedDrawable.setWidth(HmsResourcesManager.getFloatValueByResources(getContext(), ResourceTable.Float_pwk_input_item_highlight_border_width));
        mSelectedDrawable.setRadius(HmsResourcesManager.getFloatValueByResources(getContext(), ResourceTable.Float_pwk_input_item_radius));
    }

    public void setItemBorderSelectedColor(@ColorInt int itemBorderSelectedColor) {
        if (mSelectedDrawable != null) {
            mSelectedDrawable.setColor(itemBorderSelectedColor);
        }
        invalidate();
    }

    @Nullable
    public SelectedDrawable getSelectedDrawable() {
        return mSelectedDrawable;
    }

    /**
     * 设置文本字符到当前选中的输入框
     *
     * @param text 文本字符
     */
    public void updateSelectedCharAndSelectNext(final String text) {
        final Button selected = mFieldViewGroup.getFirstSelectedFieldOrNull();
        if (selected != null) {
            selected.setText(text);
            performNextFieldViewBy(selected);
        }
    }

    /**
     * 从最后一位开始删除
     */
    public void removeLastCharOfNumber() {
        final Button last = mFieldViewGroup.getLastFilledFieldOrNull();
        if (last != null) {
            last.setText(null);
            performFieldViewSetToSelected(last);
        }
    }

    /**
     * 判断是否输入完成
     *
     * @return 返回当前输入组件是否为完成状态
     */
    public boolean isCompleted() {
        // 所有显示的输入框都被填充了车牌号码，即输入完成状态
        return mFieldViewGroup.isAllFieldsFilled();
    }

    /**
     * 返回当前车牌号码是否被修改过。
     * 与通过 updateNumber 方法设置的车牌号码来对比。
     *
     * @return 是否修改过
     */
    public boolean isNumberChanged() {
        final String current = getNumber();
        return !current.equals(String.valueOf(mKeyMap.get(KEY_INIT_NUMBER)));
    }

    /**
     * 更新/重置车牌号码
     *
     * @param number 车牌号码
     */
    public void updateNumber(String number) {
        // 初始化车牌
        mKeyMap.put(KEY_INIT_NUMBER, number);
        mFieldViewGroup.setTextToFields(number);
    }

    /**
     * 获取当前已输入的车牌号码
     *
     * @return 车牌号码
     */
    public String getNumber() {
        return mFieldViewGroup.getText();
    }

    /**
     * 选中第一个输入框
     */
    public void performFirstFieldView() {
        performFieldViewSetToSelected(mFieldViewGroup.getFieldAt(0));
    }

    /**
     * 选中最后一个可等待输入的输入框。
     * 如果全部为空，则选中第1个输入框。
     */
    public void performLastPendingFieldView() {
        final Button field = mFieldViewGroup.getLastFilledFieldOrNull();
        if (field != null) {
            performNextFieldViewBy(field);
        } else {
            performFieldViewSetToSelected(mFieldViewGroup.getFieldAt(0));
        }
    }

    /**
     * 选中下一个输入框。
     * 如果当前输入框是空字符，则重新触发当前输入框的点击事件。
     */
    public void performNextFieldView() {
        final ClickMeta meta = getClickMeta(null);
        if (meta.selectedIndex >= 0) {
            final Button current = mFieldViewGroup.getFieldAt(meta.selectedIndex);
            if (!TextTool.isNullOrEmpty(current.getText())) {
                performNextFieldViewBy(current);
            } else {
                performFieldViewSetToSelected(current);
            }
        }
    }

    /**
     * 重新触发当前输入框选中状态
     */
    public void rePerformCurrentFieldView() {
        final ClickMeta clickMeta = getClickMeta(null);
        if (clickMeta.selectedIndex >= 0) {
            performFieldViewSetToSelected(mFieldViewGroup.getFieldAt(clickMeta.selectedIndex));
        }
    }

    /**
     * 设置第8位输入框显示状态
     *
     * @param setToShow8thField 是否显示
     */
    public void set8thVisibility(boolean setToShow8thField) {
        final boolean changed;
        if (setToShow8thField) {
            changed = mFieldViewGroup.changeTo8Fields();
        } else {
            changed = mFieldViewGroup.changeTo7Fields();
        }
        if (changed) {
            invalidate();
            final Button field = mFieldViewGroup.getFirstEmptyField();
            if (field != null) {
                setFieldViewSelected(field);
            }
        }
    }

    /**
     * 是否最后一位被选中状态。
     *
     * @return 是否选中
     */
    public boolean isLastFieldViewSelected() {
        return mFieldViewGroup.getLastField().isSelected();
    }

    public InputView addOnFieldViewSelectedListener(OnFieldViewSelectedListener listener) {
        mOnFieldViewSelectedListeners.add(listener);
        return this;
    }

    private void performFieldViewSetToSelected(Button target) {
        // target.performClick();
        mOnFieldViewClickListener.onClick(target);
        setFieldViewSelected(target);
    }

    private void performNextFieldViewBy(Button current) {
        final int nextIndex = mFieldViewGroup.getNextIndexOfField(current);
        performFieldViewSetToSelected(mFieldViewGroup.getFieldAt(nextIndex));
    }

    private void setFieldViewSelected(Button target) {
        for (Button btn : mFieldViewGroup.getAvailableFields()) {
            btn.setSelected(btn == target);
        }
        invalidate();
    }

    private ClickMeta getClickMeta(Button clicked) {
        int selectedIndex = -1;
        int currentIndex = -1;
        final Button[] fields = mFieldViewGroup.getAvailableFields();
        for (int i = 0; i < fields.length; i++) {
            final Button field = fields[i];
            if (currentIndex < 0 && field == clicked) {
                currentIndex = i;
            }
            if (selectedIndex < 0 && field.isSelected()) {
                selectedIndex = i;
            }
        }
        return new ClickMeta(selectedIndex, currentIndex);
    }

    private void invalidateSelectedDrawable(Canvas canvas) {
        if (mSelectedDrawable == null) {
            return;
        }
        final int count = pwkInputView.getINLChildCount();
        Component lastShown = null;
        Component selected;
        for (int i = count - 1; i >= 0; i--) {
            selected = pwkInputView.getINLComponentAt(i);
            if (lastShown == null && selected.getVisibility() == Component.VISIBLE) {
                lastShown = selected;
            }

            if (selected.getVisibility() == Component.VISIBLE && selected.isSelected()) {
                if (selected == lastShown) {
                    mSelectedDrawable.setPosition(SelectedDrawable.Position.LAST);
                } else if (i == 0) {
                    mSelectedDrawable.setPosition(SelectedDrawable.Position.FIRST);
                } else {
                    mSelectedDrawable.setPosition(SelectedDrawable.Position.MIDDLE);
                }
                final Rect rect = mSelectedDrawable.getRect();
                rect.set(selected.getLeft(), selected.getTop(), selected.getRight(), selected.getBottom());
                mSelectedDrawable.drawCanvas(canvas);
                break;
            }
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        invalidateSelectedDrawable(canvas);
    }

    @Override
    public void invalidate() {
        super.invalidate();
    }

    public interface OnFieldViewSelectedListener {
        void onSelectedAt(int index);
    }

    private static class ClickMeta {
        /**
         * 当前输入框已选中的序号
         */
        final int selectedIndex;

        /**
         * 当前点击的输入框序号
         */
        final int clickIndex;

        private ClickMeta(int selectedIndex, int currentIndex) {
            this.selectedIndex = selectedIndex;
            this.clickIndex = currentIndex;
        }

        @Override
        public String toString() {
            return "ClickMeta{" +
                    "selectedIndex=" + selectedIndex +
                    ", clickIndex=" + clickIndex +
                    '}';
        }
    }
}
